/*
Copyright (c) 2025 HeZongLun
NahidaProject is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan
PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/

#pragma once

#ifdef _WIN32
#define ExportSymbol  __declspec(dllexport)
#else
#define ExportSymbol
#endif

#include <iostream>
#include <string>
#include <stdexcept>
#include <iomanip>

namespace NahidaProject {
	class ExportSymbol Date {
	private:
		int year;
		int month;
		int day;
		bool IsLeapYear(int year) const;
		int GetDaysInMonth(int year, int month) const;
		bool IsValidDate(int y, int m, int d) const;
		long long DateToDays() const;

	public:
		Date() : year(1970), month(1), day(1) {

		}

		Date(int y, int m, int d) {
			if (!IsValidDate(y, m, d)) {
				throw std::invalid_argument("Invalid date");
			}
			year = y;
			month = m;
			day = d;
		}

		Date(const Date& other) : year(other.year), month(other.month), day(other.day) {

		}

		Date& operator=(const Date& other);
		int GetYear() const;
		int GetMonth() const;
		int GetDay() const;
		void SetDate(int y, int m, int d);
		bool operator==(const Date& other) const;
		bool operator!=(const Date& other) const;
		bool operator<(const Date& other) const;
		bool operator<=(const Date& other) const;
		bool operator>(const Date& other) const;
		bool operator>=(const Date& other) const;
		Date operator+(int days) const;
		Date operator-(int days) const;
		Date& operator+=(int days);
		Date& operator-=(int days);
		int operator-(const Date& other) const;
		Date& operator++();
		Date& operator--();
		Date operator++(int);
		Date operator--(int);
		void AddDays(int days);
		void AddMonths(int months);
		void AddYears(int years);
		int GetWeekday() const;
		std::string GetWeekdayString() const;
		std::string ToString(const std::string& format = "YYYY-MM-DD") const;
		bool IsEndOfMonth() const;
		Date EndOfMonth() const;
		Date StartOfMonth() const;
		Date EndOfYear() const;
		Date StartOfYear() const;
	};
}
